# Original code from: https://github.com/sparkfunX/Buzzard
import os
import time

from fontTools.ttLib import ttFont
from fontTools.pens.recordingPen import RecordingPen
from fontTools.pens.basePen import decomposeQuadraticSegment

from svg2mod import svg2mod, svg

class Padding():
    def __init__(self):
        self.left = 0.001
        self.right = 0.001
        self.top = 0.001
        self.bottom = 0.001        


class Buzzard():
    def __init__(self):
        self.fontName = 'FredokaOne'
        self.verbose = True
        self.scaleFactor = 0.04
        self.subSampling = 0.1
        self.traceWidth = 0.1
        self.padding = Padding()
        self.width = 0
        self.alignment = ''
        self.leftCap = ''                # Used to store cap shape for left side of tag
        self.rightCap = ''               # Used to store cap shape for right side of tag-
        self.svgText = None
        self.SystemFonts = svg.Text._system_fonts

        svg.Text.load_system_fonts()

        fnt_lib = svg.Text._system_fonts
        if fnt_lib is None:
            fnt_lib = {}

        # Load included fonts 
        typeface_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'typeface')
        for entry in os.listdir(typeface_path):
            entry_path = os.path.join(typeface_path, entry)
            
            if not entry_path.endswith('.ttf'):
                continue

            fnt_lib[os.path.splitext(os.path.basename(entry_path))[0]] = {'Path':entry_path}

    def generate(self, inString):
        self.svgText = self.renderLabel(inString)
        
        mod = Svg2Points(svg2mod.Svg2ModImport(), precision=1.0, scale_factor=1.0, center=True)
        mod.add_svg_element(self.svgText)
        mod.write()

        return mod.polys




    # ******************************************************************************
    #
    # Create SVG Document containing properly formatted inString
    #
    #
    def renderLabel(self, inString):
        # t is an svg Text element
        t = svg.Text()

        t.set_font(self.fontName)
        
        for i,s in enumerate(inString.split('\n')):
            t.add_text(s, origin=svg.Point(0, 15*i))
        
        # This needs to be called to convert raw text to useable path elements
        t.convert_to_path()
    
        # bounds check padding
        padding = self.padding
        for attr in ['left', 'right', 'top', 'bottom']:
            if getattr(padding,attr) <= 0: setattr(padding, attr, 0.001)

        bbox = t.bbox()
        height = bbox[1].y - bbox[0].y
        
        height += padding.top + padding.bottom
        width = bbox[1].x - bbox[0].x
        textWidth = (width + (self.padding.left + self.padding.right))


        fixedWidth = max(0, self.width - (self.padding.left + self.padding.right))
        width = max(width, fixedWidth)

        alignmentOffset = 0
        if self.alignment == 'Left' or fixedWidth != width:
            alignmentOffset = 0
        elif self.alignment == 'Center':
            alignmentOffset = (self.width - textWidth)/2
        elif self.alignment == 'Right':
            alignmentOffset = (self.width - textWidth)
            
        # Create outline around text 
        if (self.leftCap != '') & (self.rightCap != ''):
            pstr = "M {},{} ".format(bbox[0].x - alignmentOffset, bbox[0].y-padding.top)
            pstr += "h {} ".format(-padding.left)
            
            if self.leftCap == 'round':
                pstr += "a {},{} 0 0 0 0,{} ".format(height/2,height/2,height)
            if self.leftCap == 'square':
                pstr += "v {} ".format(height)
            if self.leftCap == 'fslash':
                pstr += "l {},{} h {} ".format(-0.3*height, height, 0.3*height)
            if self.leftCap == 'bslash':
                pstr += "h {} l {},{} ".format(-0.3*height, 0.3*height, height)
            if self.leftCap == 'pointer':
                pstr += "l {},{} l {},{} ".format(height/-3, height/2, height/3, height/2)
            if self.leftCap == 'flagtail':
                pstr += "h {} l {},{} l {},{} h {}".format(height/-3, height/3, height/2, height/-3, height/2, height/3)

            pstr += "h {} ".format(padding.left)        
            pstr += "h {} ".format(width)
            pstr += "h {} ".format(padding.right)
            
            if self.rightCap == 'round':
                pstr += "a {},{} 0 0 0 0,{} ".format(height/2, height/2,-height)
            if self.rightCap == 'square':
                pstr += "v {} ".format(-height)
            if self.rightCap == 'fslash':
                pstr += "l {},{} h {} ".format(0.3*height, -height, -0.3*height)
            if self.rightCap == 'bslash':
                pstr += "h {} l {},{} ".format(0.3*height, -0.3*height, -height)
            if self.rightCap == 'pointer':
                pstr += "l {},{} l {},{} ".format(height/3, height/-2, height/-3, height/-2)
            if self.rightCap == 'flagtail':
                pstr += "h {} l {},{} l {},{} h {}".format(height/3, height/-3, height/-2, height/3, height/-2, height/-3)
            
            pstr += "h {} ".format(-padding.right)
            pstr += "h {} z".format(-1*width)

            p = svg.Path()
            p.parse(pstr)
            t.paths.append([p])

        return t

    def create_v6_footprint(self):
        name = "kibuzzard-{:8X}".format(int(round(time.time())))
        mod = svg2mod.Svg2ModExportv6Pretty(svg2mod.Svg2ModImport(module_name=name, module_value="G***"), precision=1.0, scale_factor=self.scaleFactor, center=True)
        mod.add_svg_element(self.svgText)
        mod.write()
        return mod.raw_file_data

    def create_v5_footprint(self):
        name = "kibuzzard-{:8X}".format(int(round(time.time())))
        mod = svg2mod.Svg2ModExportPretty(svg2mod.Svg2ModImport(module_name=name, module_value="G***"), precision=1.0, scale_factor=self.scaleFactor, center=True)
        mod.add_svg_element(self.svgText)
        mod.write()
        return mod.raw_file_data

class Svg2Points( svg2mod.Svg2ModExport ):
    ''' A child of Svg2ModExport that implements
    specific functionality for creating points to render
    '''

    layer_map = {
        #'inkscape-name' : [ kicad-front, kicad-back ],
        'F.Cu' : [ 15, 15 ],
        'B.Cu' : [ 0, 0 ],
        'F.Adhes' : [ 17, 17 ],
        'B.Adhes' : [ 16, 16 ],
        'F.Paste' : [ 19, 19 ],
        'B.Paste' : [ 18, 18 ],
        'F.SilkS' : [ 21, 21 ],
        'B.SilkS' : [ 20, 20 ],
        'F.Mask' : [ 23, 23 ],
        'B.Mask' : [ 22, 22 ],
        'Dwgs.User' : [ 24, 24 ],
        'Cmts.User' : [ 25, 25 ],
        'Eco1.User' : [ 26, 26 ],
        'Eco2.User' : [ 27, 27 ],
        'Edge.Cuts' : [ 28, 28 ],
    }


    #------------------------------------------------------------------------

    def __init__(
        self,
        svg2mod_import = svg2mod.Svg2ModImport(),
        file_name = None,
        center = True,
        scale_factor = 1.0,
        precision = 20.0,
        use_mm = True,
        dpi = svg2mod.DEFAULT_DPI,
    ):
        super( Svg2Points, self ).__init__(
            svg2mod_import,
            file_name,
            center,
            scale_factor,
            precision,
            use_mm,
            dpi,
            pads = False,
        )

        self.include_reverse = False
        self.polys = []


    #------------------------------------------------------------------------

    def _get_layer_name( self, name, front ):

        layer_info = self.layer_map[ name ]
        layer = layer_info[ 0 ]
        if not front and layer_info[ 1 ] is not None:
            layer = layer_info[ 1 ]

        return layer


    #------------------------------------------------------------------------

    def _get_module_name( self, front = None ):

        if self.include_reverse and not front:
            return self.imported.module_name + "-rev"

        return self.imported.module_name


    #------------------------------------------------------------------------

    def _write_library_intro( self, cmdline ):
        pass
    
    #------------------------------------------------------------------------

    def _write_module_header(
        self, label_size, label_pen,
        reference_y, value_y, front,
    ):
        pass


    #------------------------------------------------------------------------

    def _write_module_footer( self, front ):
        pass


    #------------------------------------------------------------------------

    def _write_modules( self ):
        self._write_module( front = True )

        if self.include_reverse:
            self._write_module( front = False )



    #------------------------------------------------------------------------

    def _write_polygon( self, points, layer, fill, stroke, stroke_width ):
        self._write_polygon_filled(
            points, layer
        )


    #------------------------------------------------------------------------

    def _write_polygon_footer( self, layer, stroke_width ):
        pass


    #------------------------------------------------------------------------

    def _write_polygon_header( self, points, layer ):
        self.polys.append([])
        pass


    #------------------------------------------------------------------------

    def _write_polygon_point( self, point ):
        self.polys[-1].append(point)


    #------------------------------------------------------------------------

    def _write_polygon_segment( self, p, q, layer, stroke_width ):
        self._write_polygon_point(p)
        self._write_polygon_point(q)

